import { LocalStorage } from './storage'

export default {
  data() {
    return {
      tableId: '', // table ref

      tableForm: {}, // table request params

      tableSize: '', // table size

      tableColumns: [], // table all columns -- Column[]
      tableCheckedColumns: [], // table column prop checked -- prop[]

      tableColumnsWidth: {}, // table column width -- { prop: number | string }

      tableSortProp: '', // table sorted column's prop
      tableSortOrder: '', // table sorted column's order

      tableLoading: false, // table request status

      tablePageNum: 1, // table page index
      tablePageSize: 20, // table page size

      tableTotal: 0, // table total count
      tableData: [], // table data

      tableSelectedRows: [], // table selected rows
      tableCurrentRow: null, // table current row

      tableExcludeStorageProperties: [] // table properties exclude sotre into LocalStorage
    }
  },

  computed: {
    // table visiblity cloumns
    tableVisibleColumns() {
      if (!this.tableCheckedColumns) return []

      return this.tableColumns
        .filter(col => {
          return this.tableCheckedColumns.includes(col.prop)
        })
        .map(col => {
          return {
            ...col,
            width: this.tableColumnsWidth ? this.tableColumnsWidth[col.prop] || col.width : col.width
          }
        })
    }
  },

  watch: {
    tableId: {
      handler(val) {
        if (!val) return

        this.getTableStorage()
      },
      immediate: true
    },

    tableCheckedColumns(val) {
      this.setTableCheckedColumns(val)
    }
  },

  beforeMount() {
    this.$nextTick(() => {
      if (!this.tableCheckedColumns) {
        this.tableCheckedColumns = this.tableColumns.map(item => {
          return item.prop
        })
      }

      if (!this.tableColumnsWidth) {
        this.tableColumnsWidth = this.tableColumns.reduce((sum, col) => {
          sum[col.prop] = col.width

          return sum
        }, {})
      }
    })
  },

  activated() {
    this.setTableLayout()
  },

  methods: {
    // table method for request table data -- Promise
    tableRemoteMethod() {},

    // table method to validate request params -- <T>(function): void
    tableBeforeRequestCallback(fn) {
      fn && fn()
    },

    // table callback method after request success -- <T>(data): void
    tableSuccessCallback() {},

    // table callback method after request error -- <T>(data): void
    tableErrorCallback() {},

    // table method for refresh
    refreshTable(tableForm) {
      if (tableForm) this.tableForm = tableForm

      this.tablePageNum = this.$options.data().tablePageNum

      this.getTableData()
    },

    // table method to request table data
    getTableData() {
      if (!this.tableRemoteMethod) return false

      const fn = () => {
        this.tableLoading = true

        try {
          this.tableRemoteMethod({
            ...this.tableForm,
            pageNum: this.tablePageNum,
            pageSize: this.tablePageSize
          })
            .then(res => {
              this.tableLoading = false
              this.tableSuccessCallback && this.tableSuccessCallback(res)

              this.setTableLayout()
            })
            .catch(error => {
              this.tableLoading = false

              this.tableErrorCallback && this.tableErrorCallback(error)
            })
        } catch (error) {
          this.tableLoading = false
        }
      }

      this.tableBeforeRequestCallback ? this.tableBeforeRequestCallback(fn) : fn()
    },

    // set table page index
    setTablePageNum(pageNum) {
      this.tablePageNum = pageNum

      this.getTableData()
    },

    // set table page size
    setTablePageSize(pageSize) {
      this.tablePageSize = pageSize

      this.refreshTable()
    },

    // set table size
    setTableSize(size) {
      this.tableSize = size

      this.setTableLayout()
      this.setTableStorage('tableSize')
    },

    // set table selected rows
    setTableSelectedRows(rows) {
      this.tableSelectedRows = rows || []
    },

    // set table checked props
    setTableCheckedColumns(val) {
      this.tableCheckedColumns =
        val ||
        this.tableColumns.map(item => {
          return item.prop
        })

      this.setTableLayout()
      this.setTableStorage('tableCheckedColumns')
    },

    // set table column width
    setTableColumnWidth(newWidth, oldWidth, column) {
      const tableColumn = this.tableColumns.find(col => {
        return col.prop === column.property
      })

      if (!tableColumn) return

      this.tableColumnsWidth[tableColumn.prop] = newWidth

      this.setTableLayout()
      this.setTableStorage('tableColumnsWidth')
    },

    // set table sort prop & order
    setTableSort({ prop, order }) {
      this.tableSortProp = prop
      this.tableSortOrder = order

      this.setTableStorage('tableSortProp')
      this.setTableStorage('tableSortOrder')
    },

    // get store table from local storage
    getTableStorage(key) {
      const obj = LocalStorage.get('storeTable') || {}

      obj[this.tableId] = obj[this.tableId] || {}

      if (key) {
        const storageKey = key
          .slice(5)
          .replace(/(?:^\w|[AZ]|\b\w)/g, (word, index) => {
            return index === 0 ? word.toLowerCase() : word.toUpperCase()
          })
          .replace(/\s+/g, '')

        this[key] = obj[this.tableId][storageKey]
      } else {
        this.tableSize = obj[this.tableId].size
        this.tableCheckedColumns = obj[this.tableId].checkedColumns
        this.tableColumnsWidth = obj[this.tableId].columnsWidth
        this.tableSortProp = obj[this.tableId].sortColumn
        this.tableSortOrder = obj[this.tableId].sortOrder
      }
    },

    // set table data into local storage
    setTableStorage(key) {
      const obj = LocalStorage.get('storeTable') || {}
      obj[this.tableId] = obj[this.tableId] || {}

      if (key) {
        const storageKey = key
          .slice(5)
          .replace(/(?:^\w|[AZ]|\b\w)/g, (word, index) => {
            return index === 0 ? word.toLowerCase() : word.toUpperCase()
          })
          .replace(/\s+/g, '')

        if (!this.tableExcludeStorageProperties.includes(key)) obj[this.tableId][storageKey] = this[key]
      } else {
        if (!this.tableExcludeStorageProperties.includes('tableSize')) obj[this.tableId].size = this.tableSize

        if (!this.tableExcludeStorageProperties.includes('tableCheckedColumns'))
          obj[this.tableId].checkedColumns = this.tableCheckedColumns

        if (!this.tableExcludeStorageProperties.includes('tableColumnsWidth'))
          obj[this.tableId].columnsWidth = this.tableColumnsWidth

        if (!this.tableExcludeStorageProperties.includes('tableSortProp'))
          obj[this.tableId].sortColumn = this.tableSortProp

        if (!this.tableExcludeStorageProperties.includes('tableSortOrder'))
          obj[this.tableId].sortOrder = this.tableSortOrder
      }

      LocalStorage.set('storeTable', obj)
    },

    // relayout table
    setTableLayout() {
      if (!this.tableId || !this.$refs[this.tableId]) return

      this.$nextTick(() => {
        this.$refs[this.tableId].doLayout()
        this.$refs[this.tableId].bodyWrapper.scrollTop = 0
      })
    }
  }
}
